home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/python
-
- '''GTK Apport user interface.
-
- Copyright (C) 2007 Canonical Ltd.
- Author: Martin Pitt <martin.pitt@ubuntu.com>
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2 of the License, or (at your
- option) any later version. See http://www.gnu.org/copyleft/gpl.html for
- the full text of the license.
- '''
-
- import os.path, sys, subprocess
- from gettext import gettext as _
- try:
- import gobject, gtk, gtk.glade
- import apport.ui
- except ImportError, e:
- # this can happen while upgrading python packages
- print >> sys.stderr, 'Could not import module, is a package upgrade in progress? Error:', e
- sys.exit(1)
-
- class GTKUserInterface(apport.ui.UserInterface):
- '''GTK UserInterface.'''
-
- def w(self, widget):
- '''Shortcut for getting a widget.'''
-
- return self.widgets.get_widget(widget)
-
- def __init__(self):
- apport.ui.UserInterface.__init__(self)
-
- # load UI
- gtk.window_set_default_icon_name("apport")
- gtk.glade.textdomain(self.gettext_domain)
- self.widgets = gtk.glade.XML(os.path.join(os.path.dirname(sys.argv[0]),
- 'apport-gtk.glade'))
- self.widgets.signal_autoconnect(self)
-
- # initialize tree model and view
- self.tree_model = gtk.TreeStore(gobject.TYPE_STRING)
- self.w('treeview_reportdetails').set_model(self.tree_model)
-
- column = gtk.TreeViewColumn("Report", gtk.CellRendererText(), text=0)
- self.w('treeview_reportdetails').append_column(column)
-
- # save the original strings of the dialogs (those which contain %s,
- # which we replace later)
- self.str_heading = self.w('label_heading').get_label()
- self.str_heading_reopen = self.w('label_heading_reopen').get_label()
- self.str_heading_package_error = self.w('label_heading_package_error').get_label()
- self.str_heading_kernel_error = self.w('label_heading_kernel_error').get_label()
- self.str_radio_complete = self.w('radiobutton_complete').get_label()
- self.str_radio_reduced = self.w('radiobutton_reduced').get_label()
-
- #
- # ui_* implementation of abstract UserInterface classes
- #
-
- def ui_present_crash(self, desktop_entry):
- # adapt dialog heading and label appropriately
- if desktop_entry:
- heading = _('Sorry, %s closed unexpectedly') % desktop_entry.getName()
- elif self.report.has_key('ExecutablePath'):
- heading = _('Sorry, the program "%s" closed unexpectedly') % os.path.basename(self.report['ExecutablePath'])
- else:
- heading = _('Sorry, %s closed unexpectedly') % self.cur_package
- if desktop_entry and self.report.has_key('ExecutablePath') and \
- os.path.dirname(self.report['ExecutablePath']) in os.environ['PATH'].split(':') and \
- subprocess.call(['pgrep', '-x',
- os.path.basename(self.report['ExecutablePath']),
- '-u', str(os.geteuid())], stdout=subprocess.PIPE) != 0:
- self.w('label_heading_reopen').set_markup(self.str_heading % heading)
- d = self.w('dialog_crash_reopen')
- bl_checkbox = self.w('checkbutton_blacklist_reopen')
- else:
- self.w('label_heading').set_markup(self.str_heading % heading)
- d = self.w('dialog_crash')
- bl_checkbox = self.w('checkbutton_blacklist')
-
- # show crash notification dialog
- response = d.run()
- d.hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
- blacklist = bl_checkbox.get_active()
- if response == gtk.RESPONSE_YES:
- return {'action': 'report', 'blacklist': blacklist}
- elif response == gtk.RESPONSE_OK:
- return {'action': 'restart', 'blacklist': blacklist}
- else:
- return {'action': 'cancel', 'blacklist': blacklist}
-
- def ui_present_package_error(self):
- self.w('label_heading_package_error').set_markup(
- self.str_heading_package_error % self.report['Package'])
- response = self.w('dialog_package_error').run()
- self.w('dialog_package_error').hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
- if response == gtk.RESPONSE_YES:
- return 'report'
- else:
- return 'cancel'
-
- def ui_present_kernel_error(self):
- message = _('Your system encountered a serious kernel problem.')
- annotation = ''
- if self.report.has_key('Annotation'):
- annotation += self.report['Annotation'] + '\n\n'
- annotation += _('You can help the developers to fix the problem by reporting it.')
-
- label = self.str_heading_kernel_error % (message, annotation)
- self.w('label_heading_kernel_error').set_markup(label)
-
- response = self.w('dialog_kernel_error').run()
- self.w('dialog_kernel_error').hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
- if response == gtk.RESPONSE_YES:
- return 'report'
- else:
- return 'cancel'
-
- def ui_present_report_details(self):
- # report contents in expander
- self.tree_model.clear()
- row = 0
- for key in self.report:
- keyiter = self.tree_model.insert_before(None, None)
- self.tree_model.set_value(keyiter, 0, key)
-
- valiter = self.tree_model.insert_before(keyiter, None)
- if not hasattr(self.report[key], 'gzipvalue') and \
- hasattr(self.report[key], 'isspace') and \
- not self.report._is_binary(self.report[key]):
- self.tree_model.set_value(valiter, 0, self.report[key])
- # expand the row if the value has less than 5 lines
- if len(filter(lambda c: c == '\n', self.report[key])) < 4:
- self.w('treeview_reportdetails').expand_row(row, False)
- else:
- self.tree_model.set_value(valiter, 0, _('(binary data)'))
-
- row += 1
-
- # complete/reduced radio buttons
- if self.report.has_key('CoreDump'):
- self.w('radiobutton_complete').set_label(self.str_radio_complete %
- self.format_filesize(self.get_complete_size()))
- self.w('radiobutton_reduced').set_label(self.str_radio_reduced %
- self.format_filesize(self.get_reduced_size()))
- if self.report.has_useful_stacktrace():
- self.w('radiobutton_complete').set_sensitive(True)
- self.w('radiobutton_complete').show()
- self.w('radiobutton_reduced').show()
- else:
- self.w('radiobutton_complete').set_sensitive(False)
- self.w('radiobutton_reduced').hide()
- else:
- self.w('radiobutton_complete').hide()
- self.w('radiobutton_reduced').hide()
-
- response = self.w('dialog_bugreport').run()
- self.w('dialog_bugreport').hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- if response == gtk.RESPONSE_OK:
- if self.w('radiobutton_complete').get_active():
- return 'full'
- else:
- return 'reduced'
- else:
- return 'cancel'
-
- def ui_info_message(self, title, text):
- md = gtk.MessageDialog(type=gtk.MESSAGE_INFO,
- buttons=gtk.BUTTONS_CLOSE, message_format=text)
- md.set_title(title)
- md.run()
- md.hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- def ui_error_message(self, title, text):
- md = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
- buttons=gtk.BUTTONS_CLOSE, message_format=text)
- md.set_title(title)
- md.run()
- md.hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- def ui_start_info_collection_progress(self):
- self.w('progressbar_information_collection').set_fraction(0)
- self.w('window_information_collection').show()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- def ui_pulse_info_collection_progress(self):
- self.w('progressbar_information_collection').pulse()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- def ui_stop_info_collection_progress(self):
- self.w('window_information_collection').hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- def ui_start_upload_progress(self):
- '''Open a window with an definite progress bar, telling the user to
- wait while debug information is being uploaded.'''
-
- self.w('progressbar_upload').set_fraction(0)
- self.w('window_report_upload').show()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- def ui_set_upload_progress(self, progress):
- '''Set the progress bar in the debug data upload progress
- window to the given ratio (between 0 and 1, or None for indefinite
- progress).
-
- This function is called every 100 ms.'''
-
- if progress:
- self.w('progressbar_upload').set_fraction(progress)
- else:
- self.w('progressbar_upload').set_pulse_step(0.1)
- self.w('progressbar_upload').pulse()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- def ui_stop_upload_progress(self):
- '''Close debug data upload progress window.'''
-
- self.w('window_report_upload').hide()
- while gtk.events_pending():
- gtk.main_iteration(False)
-
- #
- # Event handlers
- #
-
- def on_progress_window_close_event(self, widget, event=None):
- self.w('window_information_collection').hide()
- self.w('window_report_upload').hide()
- sys.exit(0)
- return True
-
- def on_expander_details_activate(self, widget):
- # signal is sent before actually expanding/collapsing, thus this
- # requires negation
- self.w('dialog_bugreport').set_resizable(not self.w('expander_details').get_expanded())
- while gtk.events_pending():
- gtk.main_iteration(False)
- return True
-
- if __name__ == '__main__':
- app = GTKUserInterface()
- app.run_argv()
-